/*
 * EigenfaceTrainingSet.hpp
 *
 *  Created on: 31.05.2014
 *      Author: philipp
 */

#ifndef EIGENFACETRAININGSET_HPP_
#define EIGENFACETRAININGSET_HPP_

#include <vector>
#include <opencv2/opencv.hpp>
#include "Misc.hpp"
#include "FileHelper.hpp"

/*
 * Eigenface algorythm class for easier usage.
 */
class EigenfaceTrainingSet {
public:
	/*
	 * Every input face can be classified to be either known, unknown or not to be a face at all.
	 */
	enum FaceClassification {
		FC_KNOWN, FC_UNKNOWN, FC_NOFACE
	};

private:
	double noFaceThreshold, unknownFaceThreshold;
	int imageSizeX, imageSizeY;
	cv::Mat eigenfaces, eigenvalues, averageImage, averageFaceWeight;
	std::vector<cv::Mat> trainingImages, faceWeights;
private:
	/*
	 * converts the input image to a vector with only one dimension.
	 */
	cv::Mat imageToEigenfaceVector(const cv::Mat &screenshot) const;
	/*
	 * converts the input vector back to a normal image with two dimensions.
	 */
	cv::Mat eigenfaceVectorToImage(const cv::Mat &vector) const;
	/*
	 * builds the eigenface training set matrix, every column represents one image vector.
	 */
	cv::Mat buildEigenfacesTrainingSet(
			const std::vector<cv::Mat> &columns) const;
	/*
	 * computes the mean image of all input images and returns the result.
	 */
	cv::Mat calculateMeanImage(const std::vector<cv::Mat> &images) const;
	/*
	 * substracts the mean image from all columns (image vectors) within the training set matrix.
	 */
	void substractMeanFromTrainingSet(cv::Mat &trainingSet,
			const cv::Mat &meanImage) const;
	/*
	 * normalizes a vector to have a length of 1.
	 */
	cv::Mat normalizeVector(const cv::Mat &vector) const;
	/*
	 * calculates the eigenface weights for the input image.
	 * those weights describe the contrubution of every eigenface to the input image.
	 */
	cv::Mat calculateFaceWeights(const cv::Mat &image) const;
public:
	/*
	 * constructor for the eigenface algorythm class.
	 * requires a vector of training images and the image computation size to be used.
	 */
	EigenfaceTrainingSet(const std::vector<cv::Mat> &trainingImages,
			int imageSizeX, int imageSizeY);
	/*
	 * destructor.
	 */
	~EigenfaceTrainingSet();
	/*
	 * returns a const ref to the calculated mean image.
	 */
	const cv::Mat &getAverageImage() const;
	/*
	 * returns the amount of generated eigenfaces.
	 */
	int getEigenfaceCount() const;
	/*
	 * returns the eigenface with the specified id.
	 * the eigenfaces are sorted by their eigenvalues in descending order. (id 0 has the highest eigenvalue)
	 */
	cv::Mat getEigenface(int id) const;
	/*
	 * saves the mean image, the eigenfaces and the training images as files in the program root folder for debugging.
	 */
	void createDebugImages() const;
	/*
	 * returns a const ref to the training images.
	 */
	const std::vector<cv::Mat> &getTrainingImages() const;
	/*
	 * classifies an input face as either known, unknown or no face
	 * (see FaceClassification enum for possible return values)
	 */
	FaceClassification categorizeFace(const cv::Mat &image) const;
	/*
	 * sets the threshold value to when a face should be classified as "no face".
	 * the threshold value is calculated as minimal euclidian distance to all known face images.
	 * if the value is >= the set threshold, categorizeFace will return FC_NOFACE
	 */
	void setNoFaceThreshold(double threshold);
	/*
	 * sets the threshold value to when a face should be classified as "unknown face".
	 * the threshold value is calculated as minimal euclidian distance to all known face images.
	 * if the value is >= the set threshold but smaller than the no face threshold, categorizeFace will return FC_UNKNOWN
	 */
	void setUnknownFaceThreshold(double threshold);
};

#endif /* EIGENFACETRAININGSET_HPP_ */
